﻿using System;
using System.Collections.Generic;
using System.Linq;
using UMC.Data;
using UMC.Wiki.Entities;
using UMC.Web;

namespace UMC.Wiki
{
    public class DataFactory
    {

        static DataFactory()
        {
            HotCache.Register<Project>("Id").Register("Code").Register("AppKey", "Id");
            HotCache.Register<ProjectItem>("Id").Register("project_id", "Code");
            HotCache.Register<ProjectMember>("user_id", "project_id").Register("project_id", "AuthType", "CreationTime", "user_id");
            HotCache.Register<Comment>("Id").Register("ref_id", "Id").Register("user_id", "ref_id", "Id")
                .Register("for_id", "Id");

            HotCache.Register<Portfolio>("Id").Register("project_item_id", "Id");
            HotCache.Register<Subject>("Id").Register("project_id", "ReleaseTime", "Id").Register("project_item_id", "Id")
            .Register("portfolio_id", "Id").Register("project_item_id", "Code").Register("ReleaseTime", "Id");


            HotCache.Register<Proposal>("ref_id", "user_id").Register("user_id", "ref_id");
            HotCache.Register<Attention>("Id");
            HotCache.Register<SubjectContent>("Id");
            HotCache.Register<ProjectAccess>("sub_id", "user_id").Register("user_id", "sub_id");

            HotCache.Register<ProjectReader>("project_id", "reader_id").Register("reader_id", "project_id");
            HotCache.Register<ProjectDynamic>("user_id", "Time").Register("project_id", "Time", "user_id");
            HotCache.Register<SubjectTipOff>("sub_id", "user_id").Register("user_id", "sub_id");
            HotCache.Register<ProjectBlock>("ref_id", "user_id").Register("user_id", "ref_id");

            //System.Net.WebSockets.HttpListenerWebSocketContext


        }
        static DataFactory _Instance = new DataFactory();
        public static void Instance(DataFactory dataFactory)
        {
            _Instance = dataFactory;
        }
        public static DataFactory Instance()
        {
            return _Instance;
        }
        public virtual Project Project(String code)
        {
            return HotCache.Get(new Project
            {
                Code = code
            });

        }

        public virtual Project Project(ulong sid)
        {
            return HotCache.Get(new Project
            {
                Id = sid
            });

        }

        public virtual void Delete(SubjectContent content)
        {
            HotCache.Delete(content);

        }
        public virtual void Delete(Comment comment)
        {
            HotCache.Delete(comment);

        }
        public virtual void Delete(Subject subject)
        {
            HotCache.Delete(subject);

        }
        public virtual void Delete(ProjectItem comment)
        {
            HotCache.Delete(comment);
        }
        public virtual Subject[] Follow(Subject search, int start, int limit, out int nextIndex)
        {
            int next;
            var searcher = HotCache.Cache<Subject>().Search<Subject>();
            var list = new List<object>();
            //searcher.In()
            var ms = HotCache.Find(new ProjectMember { user_id = search.user_id.Value }, 0, 5000, out next);
            for (var i = 1; i < ms.Length; i++)
            {
                list.Add(ms[i].project_id.Value);
            }
            if (ms.Length > 0)
            {
                searcher.Equal(new Subject { Status = 1 });
                searcher.In(new Subject { project_id = ms[0].project_id.Value }, list.ToArray());
                if (String.IsNullOrEmpty(search.Title) == false)
                {
                    searcher.Like(new Subject { Title = search.Title });
                }
                return searcher.Search(new Subject { ReleaseTime = DateTime.Now }, true, start, limit, out nextIndex);
            }
            nextIndex = -1;
            return new Subject[0];
        }

        public virtual ProjectItem ProjectItem(ulong project_id, String code)
        {
            return HotCache.Get(new ProjectItem { project_id = project_id, Code = code });

        }
        public virtual ProjectItem[] ProjectItem(Project project)
        {
            int i;
            return HotCache.Find(new ProjectItem
            {
                project_id = project.Id
            }, 0, 200, out i).OrderBy(r => r.Sequence ?? 0).ToArray();


        }
        public virtual ProjectItem[] ProjectItem(params ulong[] sid)
        {
            if (sid.Length > 0)
                return HotCache.Cache<ProjectItem>().Find(new ProjectItem()
                 , "Id", sid).OrderBy(r => r.Sequence ?? 0).ToArray();
            return new ProjectItem[0];
        }

        internal void Delete(Portfolio portfolio)
        {
            HotCache.Delete(portfolio);
        }

        public virtual Project[] Projects(Guid userid, params WebAuthType[] auths)
        {

            var ids = new List<ulong>();
            int next;
            var ls = HotCache.Find(new ProjectMember { user_id = userid }, 0, 500, out next);
            if (auths.Length > 0)
            {
                foreach (var k in ls)
                {
                    if (auths.Contains(k.AuthType ?? WebAuthType.Guest))
                    {
                        ids.Add(k.project_id.Value);
                    }

                }
            }
            else
            {
                foreach (var k in ls)
                {
                    ids.Add(k.project_id.Value);
                }
            }
            if (ids.Count > 0)
            {
                return HotCache.Find(new Project { }, "Id", ids);
            }
            return new Project[0];

        }


        public virtual Project[] Projects(params ulong[] ids)
        {
            if (ids.Length > 0)
            {
                return HotCache.Find(new Project { }, "Id", ids);
            }
            return new Project[0];
        }
        public virtual Project[] Projects(Guid appKey)
        {
            return HotCache.Find(new Project { AppKey = appKey });//, "AppKey",new Guid appKey);

        }
        public virtual Subject Subject(ulong sid)
        {
            return HotCache.Get(new Subject { Id = sid });

        }
        public virtual Subject Subject(ulong project_id, ulong project_item_id, String code)
        {

            var f = HotCache.Find(new Subject { project_item_id = project_item_id }, "Code", new String[] { code });
            if (f.Length > 0)
            {
                return f[0];
            }
            return null;

        }
        public virtual Subject[] Subject(params ulong[] ids)
        {
            return HotCache.Find(new Subject { }, "Id", ids);
        }
        public virtual Subject[] Subject(params Portfolio[] portfolios)
        {

            var ids = new List<ulong>();
            UMC.Data.Utility.Each(portfolios, dr =>
            {
                ids.Add(dr.Id.Value);
            });
            if (ids.Count > 0)
            {
                return HotCache.Find(new Subject { }, "portfolio_id", ids);
            }
            return new Subject[0];
        }
        public virtual Proposal Proposal(Guid userId, ulong refId)
        {

            return HotCache.Get(new Proposal { ref_id = refId, user_id = userId });

        }
        public virtual Portfolio Portfolio(ulong portfolioid)
        {
            return HotCache.Get(new Portfolio { Id = portfolioid });

        }
        public virtual Attention Attention(Guid userid)
        {
            return HotCache.Get(new Attention { Id = userid });
        }
        public virtual Attention[] Attention(params Guid[] userids)
        {
            return HotCache.Find(new Attention { }, "Id", userids);
        }
        public virtual Portfolio[] Portfolio(ProjectItem projectItem)
        {
            return HotCache.Find(new Portfolio { }, "project_item_id", new ulong[] { projectItem.Id.Value });

        }
        public virtual void Put(SubjectContent content)
        {
            HotCache.Put(content);
        }
        public virtual void Put(Attention attention)
        {
            HotCache.Put(attention);
        }
        public virtual void Put(ProjectAccess access)
        {
            var s = HotCache.Get(access);
            if (s != null)
            {
                access.Times = (s.Times ?? 1) + 1;
                access.LastAccessTime = DateTime.Now;
            }
            else
            {
                access.CreationTime = DateTime.Now;
                access.Times = 1;
                access.LastAccessTime = DateTime.Now;
            }
            HotCache.Put(access);
        }
        public virtual void Put(Project project)
        {
            HotCache.Put(project);

        }
        public virtual void Put(ProjectItem projectItem)
        {

            HotCache.Put(projectItem);
        }
        public virtual void Put(Portfolio portfolio)
        {

            HotCache.Put(portfolio);
        }

        public virtual void Put(ProjectDynamic projectDynamic)
        {
            int n;
            var m = HotCache.Find(new ProjectDynamic { user_id = projectDynamic.user_id.Value }, true, 0, 1, out n);
            if (m.Length > 0)
            {
                if (m[0].refer_id != projectDynamic.refer_id)
                {
                    HotCache.Put(projectDynamic);
                }
            }
            else
            {
                HotCache.Put(projectDynamic);
            }
        }
        public virtual bool Subject(Proposal proposal)
        {

            var l = HotCache.Get(new Proposal { user_id = proposal.user_id.Value, ref_id = proposal.ref_id.Value });
            if (l == null)
            {
                HotCache.Put(proposal);

                var sub = HotCache.Get(new Subject { Id = proposal.ref_id.Value });
                if (sub != null)
                {
                    var favs = sub.Favs ?? 0;
                    if (favs < 0)
                    {
                        favs = 0;
                    }
                    HotCache.Put(new Subject { Id = proposal.ref_id.Value, Favs = favs + 1 });
                }
                return true;
            }
            else
            {

                HotCache.Delete(proposal);
                var sub = HotCache.Get(new Subject { Id = proposal.ref_id.Value });
                if (sub != null)
                {
                    HotCache.Put(new Subject { Id = proposal.ref_id.Value, Favs = (sub.Favs ?? 0) - 1 });
                }
                return false;
            }
        }

        public virtual bool Comment(Proposal proposal)
        {

            var l = HotCache.Get(new Proposal { user_id = proposal.user_id.Value, ref_id = proposal.ref_id.Value });
            if (l == null)
            {
                HotCache.Put(proposal);

                var sub = HotCache.Get(new Comment { Id = proposal.ref_id.Value });
                if (sub != null)
                {
                    HotCache.Put(new Comment { Id = proposal.ref_id.Value, Effective = (sub.Effective ?? 0) + 1 });
                }
                return true;
            }
            else
            {

                HotCache.Delete(proposal);
                var sub = HotCache.Get(new Comment { Id = proposal.ref_id.Value });
                if (sub != null)
                {
                    HotCache.Put(new Comment { Id = proposal.ref_id.Value, Effective = (sub.Effective ?? 0) - 1 });
                }
                return false;
            }
        }
        public virtual void Delete(ProjectMember member)
        {

            HotCache.Delete(member);
        }

        public virtual void Put(Comment comment, bool isNew)
        {
            HotCache.Put(comment);
            if (isNew)
            {
                if (comment.for_id == 0)
                {
                    var sub = HotCache.Get(new Subject { Id = comment.ref_id.Value });
                    if (sub != null)
                    {
                        HotCache.Put(new Subject { Id = comment.ref_id.Value, Reply = (sub.Reply ?? 0) + 1, last_command_id = comment.Id });
                    }


                }
            }
        }

        public virtual Comment Comment(ulong id)
        {
            return HotCache.Get(new Comment { Id = id });

        }
        public virtual Comment[] Comments(params ulong[] ids)
        {
            if (ids.Length > 0)
            {
                return HotCache.Find(new Comment { }, "for_id", ids).OrderBy(d => d.CommentDate).ToArray();
            }
            return new Comment[0];
        }
        public virtual void Block(ProjectBlock block)
        {
            HotCache.Put(block);
        }
        public virtual void TipOff(SubjectTipOff tipOff)
        {
            HotCache.Put(tipOff);


            var sub = HotCache.Get(new Subject { Id = tipOff.sub_id.Value });
            if (sub != null)
            {
                HotCache.Put(new Subject { Id = tipOff.sub_id.Value, TipOffs = (sub.TipOffs ?? 0) + 1 });//, last_command_id = comment.Id });
            }

        }
        public virtual Subject[] Search(Subject subject, int start, out int nextIndex, int limit)
        {
            var searcher = HotCache.Cache<Subject>().Search<Subject>();

            searcher.Equal(new Subject
            {
                // project_id = subject.project_id,
                project_item_id = subject.project_item_id,
                portfolio_id = subject.portfolio_id,
                Status = subject.Status,
                user_id = subject.user_id
            });
            if (String.IsNullOrEmpty(subject.Title) == false)
            {
                searcher.And().Or().Like(new Subject { Title = subject.Title, Description = subject.Title });
            }
            if (subject.project_id.HasValue)
            {
                return searcher.Query(new Subject { project_id = subject.project_id.Value }, true, start, limit, out nextIndex);
            }
            else
            {
                return searcher.Search(new Subject { ReleaseTime = DateTime.Now }, true, start, limit, out nextIndex);
            }

        }
        public virtual Proposal[] Search(Proposal search, int start, out int nextIndex, int limit)
        {
            return HotCache.Find(search, start, limit, out nextIndex);
        }
        public virtual Comment[] Search(Comment comment, bool isAsc, int start, out int nextIndex, int limit)
        {
            if (comment.ref_id.HasValue || comment.user_id.HasValue)
            {
                return HotCache.Cache<Comment>().Search<Comment>().Equal(new Comment { for_id = 0 })
                     .Query(new Comment { ref_id = comment.ref_id, user_id = comment.user_id }, !isAsc, start, limit, out nextIndex);

            }
            else if (comment.for_id.HasValue && comment.for_id != 0)
            {
                return HotCache.Find(new Comment { for_id = comment.for_id }, !isAsc, start, limit, out nextIndex);

            }
            return HotCache.Find(comment, !isAsc, start, limit, out nextIndex);

        }
        public virtual ProjectAccess[] Search(ProjectAccess access, int start, out int nextIndex, int limit)
        {
            return HotCache.Find(access, true, start, limit, out nextIndex);


        }
        public virtual ProjectDynamic[] Search(ProjectDynamic comment, int start, out int nextIndex, int limit)
        {

            return HotCache.Find(comment, true, start, limit, out nextIndex);


        }
        public virtual ProjectMember[] Search(ProjectMember member, int start, out int nextIndex, int limit)
        {
            if (String.IsNullOrEmpty(member.Alias) == false)
            {
                return HotCache.Cache<ProjectMember>().Search<ProjectMember>().Like(new ProjectMember { Alias = member.Alias })
                     .Query(new ProjectMember { project_id = member.project_id }, true, start, limit, out nextIndex);
            }
            return HotCache.Find(member, true, start, limit, out nextIndex);

        }
        public virtual ProjectDynamic Dynamic(uint time, Guid user_id)
        {
            return HotCache.Get(new ProjectDynamic { Time = time, user_id = user_id });

        }
        public virtual Subject[] Subject(Portfolio portfolio)
        {
            return HotCache.Find(new Subject { }, "portfolio_id", new ulong[] { portfolio.Id.Value });
        }
        public virtual SubjectContent Content(ulong subid)
        {
            return HotCache.Get(new SubjectContent
            {
                Id = subid
            });
        }
        public virtual Subject Subject(ulong projectItemId, String code)
        {

            return HotCache.Get(new Subject { project_item_id = projectItemId, Code = code });

        }
        public virtual void New(Subject subject)
        {
            subject.Favs = 0;
            subject.TipOffs = 0;
            subject.Reply = 0;
            subject.Score = 0;
            subject.Look = 0;

            HotCache.Put(subject);

        }
        public virtual Subject[] Spread(Subject subject)
        {
            return new Subject[0];
        }
        // public virtual bool IsAdver(Guid Userid)
        // {
        //     return false;
        // }

        public virtual ProjectReader[] ProjectReader(Guid readerId)
        {

            return HotCache.Find(new ProjectReader { reader_id = readerId });
        }//, "portfolio_id", new ulong[] { portfolio.Id.Value });
        public virtual ProjectReader ProjectReader(Guid readerId, ulong project_id)
        {
            return HotCache.Get(new Entities.ProjectReader { project_id = project_id, reader_id = readerId });
        }
        public virtual void Put(ProjectReader subject)
        {
            HotCache.Put(subject);
        }


        public virtual void Put(Subject subject)
        {
            HotCache.Put(subject);

        }
        public virtual ProjectMember[] ProjectMember(ulong project_id, params Web.WebAuthType[] authTypes)
        {

            return HotCache.Find(new ProjectMember
            {
                project_id = project_id,
            }, "AuthType", authTypes);

        }

        public virtual ProjectMember[] ProjectMember(Guid userid)
        {
            return HotCache.Find(new ProjectMember
            {
                user_id = userid,
            });
        }
        public virtual ProjectMember ProjectMember(ulong project_id, Guid userid)
        {
            return HotCache.Get(new ProjectMember
            {
                project_id = project_id,
                user_id = userid
            });
        }
        public virtual void Put(ProjectMember projectMember)
        {
            HotCache.Put(projectMember);
        }

        public virtual ProjectItem ProjectItem(ulong itemId)
        {
            return HotCache.Get(new ProjectItem
            {
                Id = itemId
            });
        }
    }
}
